# Tutorial

## blink with LED

This is platform-neural tutorial, although hardware implementation refers to
arduino. The full code can be found at `examples/atmega328p/blink-led.cpp`. In
this example the blinking with LED using `rotor-light`.

Let's start from the inclusion of headers:

```
#include <rotor-light.hpp>
```

All further interactions with the framework is done via `rl` namespace

```
namespace rl = rotor_light;
```

In this example, there is only single message - `BlinkCommand`. It is good
practice to define messages in it's own namespace, as it is much more
convenient to deail with messages later (handle and send).

```
namespace message {

struct BlinkCommand : rl::Message {            // (1)
  static constexpr auto type_id = __LINE__;    // (2)
  using rl::Message::Message;                  // (3)
  rl::MessageTypeId get_type_id() const override {  // (4)
    return type_id; }
  };

} // namespace message
```

The `BlinkCommand` message have to be derived from `rotor_ligth` `Message` (1),
and as the `BlinkCommand` has no payload, it just reuses its parent
consturctor (`using rl::Message::Message`, (3)).

As the `rotor_ligth` does not uses RTTI it should somehow identify
message types at runtime. That's why overriden `get_type_id()` method (4)
should be available on every message type. `rotor_light` does not care
how you, as the user, define your message type, the only requirement is the
uniqueness of them. The easiest way to achieve that is just have line (2)
in every message type definition, and group all used messages in a single
header file.

Let's move to the blinker actor code; as it is rather small, it is shown
entirely:

```
struct Blinker : rl::Actor<2> {  // (5)
using Parent = Actor<2>;  // (6)

void initialize() override {  // (7)
  subscribe(&Blinker::on_blink_command);  // (8)
  Parent::initialize();                   // (9)
}


  void advance_start() override {  // (10)
    Parent::advance_start();       // (11)
    blink();                       // (12)
  }

  void blink() {
    toggle_led();                                  // (13)
    add_event(delay, [](void *data) {              // (14)
        auto self = static_cast<Blinker *>(data);  // (15)
        self->send<message::BlinkCommand>(0, id);  // (16)
    }, this);
  }

void on_blink_command(message::BlinkCommand &msg) {  // (17)
  blink();
}

rl::Duration delay;  // (18)
};
```

First, your own actor have to inherit from `rl::Actor` (5). The magic number `2` is
used for preallocation space for actor's message handlers: the one handler from the
base class defined by the framework (might be changed in the future), and the other
one use the user-provided `on_blink_command`. The alias (6) makes it more convenient
to refer the base class in the future.

To react on the `BlinkCommand` message, the actor should subscribe to it (8). The
proper place to do that is to override `initialize()` method (7), of the parent class.
Of course, parent class **must** be initialized too, that's why don't forget to
invoke its initialization (9).

When actor is ready, its `advance_start()` (10) is invoked; as usually correspondig
parents method should be called (11) and the initial blink (12) is performed. In
the implementation of `blink()` the platform-dependent LED toggle is done at (13),
and then delayed the same method invokation is scheduled (14-16). In (14) the
capture-less lambda is scheduled to be invoked with `this` as the parameter when
`delay` (18) amount of time passes. The lambda *must* be capture-less. After casting
back `void*` to the actor class (15), it sends self a `BlinkCommand` message (16)
using zero-priority queue. The `id` parameter is the destination actor address;
which is the `Blinker` (self) address here. The destination address can also be
multiple actors (i.e. it is mask).

Each time the `BlinkCommand` is received (17), the `blink()` method is invoked, and
the procedure above repeats again.

Next, the application-wide compile-time configuration should be made:

```
using Storage = rl::traits::MessageStorage<rl::message::ChangeState,    // (18)
                                           rl::message::ChangeStateAck,
                                           message::BlinkCommand>;
using Queue = rl::Queue<Storage, 5>; /* upto 5 messages in 1 queue */   // (19)
using Planner = rl::Planner<2>;      /* upto 2 time events */           // (20)
using Supervisor = rl::Supervisor<                                      // (21)
                            rl::SupervisorBase::min_handlers_amount,
                            Blinker>;
```

`rotor-light` uses queues to store and process messages. There are no dynamic
allocations, so, all sizes have to be known at compile-time, including the sizes
of all used messages. The `Storage` helper (18) is used to determine the maximum
allowed storage size per message: here **all messages** in the application
should be enumerated, i.e. messages from the framework and user-defined.

Next, the application queue (or master queue) should be defined (19). It uses
`Storage` and the magic number `5`, which pre-allocates space for queue with
**zero-priority** for 5 messages. All `rotor-light` messages are put into that
queue, but user-defined messages might use different queues. Queues with
higher priorities are processed earlier than queues with lower priorities. So,
to define master queue with two subqueues (priorities 0 and 1) with sizes
enought to store 15 and 10 messages respectively, the following code should
be used

```
using Queue = rl::Queue<Storage, 15, 10>;
```

What is the recommended queue sizes? Well, it is completely application defined, but
for `rotor-light` messages there should be enought space to store `N * 2` messages,
where `N` is the total number of actors (including supervisors).

What happens, if a queue is full? The next send mesage is simply discarded, you'll
be notified about that as the `send()` method returns `false`. If the discarded
message is `rotor-light` message, then the framework behavior is undefined. So,
either do not overload default queue (i.e. with zero-priority), or use different
queues for user-messages. NB: there is a spike of `rotor-light` messages only
during (re)starting supervisor; when everything is *operational* there is almost no
framework mesages.

The Planner (20) is used to schedule future events, like it is shown at `add_event`
(14). The number in angle braces defines planner capacity at compile-time. When event
time arrives, it is removed from the planner. Please note, that `rotor-light` does
not schedules any events into the planner, so its capacity and usage is completely
controlled by the user code.

How the framework interracts with the planner? If the root supervisor is used in
*poll mode*, then, when there are no more messages left, the current time is
requested, and all timed out event handlers are executed. Then the special message
`refresh-time` is send to the supervisor and the procedure repeates enlessly.
Indirectly, this is similar to the code like:

```
while (true) {
  while (has_messages()) {
    auto& message = get_front_message();
    process(message);
    pop_front_message();
  }
  // (22)
  auto now = get_now();
  while (has_expired_events(now)) {
    auto& event = get_next_expired_event(now);
    fire_event(event);
    pop_event(event);
  }
    
```

If the *await mode* is used, then user code should implement the whole `while` loop
above and the event awaiting (22) code. This makes it possible to enter into
power-save mode and wake up on external timer or interrupt. See `*-await.cpp`
examples.

In the line (22) the used supervisor is defined: the amount of handlers is specified
(the same as for actor at (5), as each supervisor is an actor) and all its
child actors (including other supervisors) are enumerated. The only `Blinker`
child actor is specified in the current example.

Let's move forward. In the folowing code `rotor-light` global variables are
allocated:

```
Queue queue;
Planner planner;
rl::Context context{&queue, &planner, &get_now};
Supervisor sup;
```

All of them can be allocated on the stack, but for the supervisor it is, probably,
the bad idea, because most likely you'll need to access actors from some other
global functions, i.e. ISR, and that can be done only via global supervisor
instance. That might be not obvious, that the supervisor above allocates space for
all its child actors, i.e. *supervisor contains and owns child actors*.

The `get_now()` function pointer refers to a function with the following signature:

```
using TimePoint = int64_t;
using NowFunction = TimePoint (*)();
```

It is the only link to the underlying hardware or system. The function should return
current time; the meaning of "current time" (`TimePoint`) is completely user
specific (i.e. it can point to seconds, milliseconds, microseconds etc.). The only
requirement to the function, that it should be **monotonic**, i.e. do not decrease
nor wrap each next `TimePoint` compared to the previous one. The implementation
of the function is completely platform- or hardware-specific. For the arduino
example it returns the number of microseconds passed since board boot.

The final piece of the current example is:

```
int main(int, char **) {
  app_hw_init();

  /* setup */
  sup.bind(context);                        // (23)
  auto blinker = sup.get_child<0>();        // (24)
  blinker->delay = rl::Duration{250000};    // (25)
  /* let it polls timer */
  sup.start(true);                          // (26)

  /* main cycle */
  sup.process();                            // (27)
  return 0;
}

```

The context binding (23) let the supervisor know pre-allocated queues, planner and
the `get_now()` function. During context binding all actors get their unique ids,
which can be used. After that individual actors can be accessed (24) with zero
runtime overhead (as it uses `std::get` under the hood) and additional actors
setup can be performed here (26), i.e. delay 1/4 of seconds between LED toggle.

Please note, that setup phase (23-26) need to be performed **only once** despite
of possible mutiple actors restarts, i.e. actor identities are preserved during
object lifetimes.

Then, the whole machinery receive initial impulse (26). The `true` value here means
usage of the "poll mode" (see above), i.e. endlessly send self a `refresh-timer`
message, get time, and fire the timed-out events.

In the line (27) supervisor actually starts processing messages, and probably never
exits as soon as everything is going as expected. In the case of *failure
escalation*, i.e. as it tried all possible restarts of actors to recover the
failure, there is nothing left to do than exit and the whole board restart.

## ping-pong messaging, poll timer

In this example how to doi messaging with `rotor-light` is demonstrated: `ping`
message is sent from `pinger` actor to `ponger` actor. The `ponger` actor will
reply back with `pong`  message, then after some delay `pinger` actor repeats
the same procedure. The full code can be found at
`examples/atmega328p/ping-pong-poll.cpp`.

First of all used messages should be defined:

```
namespace message {
struct Ping : rl::Message {
  using Message::Message;
  static constexpr auto type_id = __LINE__;
  rl::MessageTypeId get_type_id() const override { return type_id; }
};

struct Pong : rl::Message {
  using Message::Message;
  static constexpr auto type_id = __LINE__;
  rl::MessageTypeId get_type_id() const override { return type_id; }
};
} // namespace message

```

The `ping` and `pong` messages are content-less, why there is need of them for all?
Because there is need to demonstrate how to send and receive messages.

The `Pinger` actor code is:

```
struct Pinger : rl::Actor<2> {
  using Parent = Actor<2>;

  void initialize() override {
    subscribe(&Pinger::on_pong); // (28)
    Parent::initialize();
  }

  void advance_start() override {  // (29)
    Parent::advance_start();       // (30)
    ping();                        // (31)
  }

  void ping() {                         // (32)
    /* toggle led */
    PORTB ^= (1 << LED);
    send<message::Ping>(0, ponger_id);  // (33)
  }

  void on_pong(message::Pong &) {          // (34)
    add_event(500000, [](void *data) {     // (35)
      static_cast<Pinger *>(data)->ping();
    }, this);
  }

  rl::ActorId ponger_id;   // (36)
};

```

As usually, the `initialize()` should be overriden to subscribe on `pong` messages
(28). The `pinger` actor plays an *active role*, i.e. it sends initial `ping`
message. This is performed in the overriden `advance_start()` method (29), which is
invoked as soon as the actor is ready: the default implementation machinery is
invoked (30), and for convenience `ping()` (31) method is called. The `ping()` (32)
method implementation is simple: after LED toggle, it sends the `ping` message (33).

The `send` method parameters are: the message type (`message::Ping`) template
parameter, message priority (aka destination queue) - `0`, and the destination
actor(s) - ponger actor id, defined at (36). If there are additional message params,
specified in the message type constructor, they should go here.

As soon as `pong` reply is received (34), the ping procedure with LED toggle
is rescheduled after 500000 microseconds (i.e. 0.5 second) at (35).

The `ponger` actor code is rather trivial:

```
struct Ponger : rl::Actor<2> {
  using Parent = Actor<2>;

  void initialize() override {
    subscribe(&Ponger::on_ping);
    Parent::initialize();
  }
  void on_ping(message::Ping &) {
    send<message::Pong>(0, pinger_id);  // (37)
  }
  rl::ActorId pinger_id;   // (38)
};

```

as soon `ping` message is received, it replies back (37) with `pong` message. Please
note, while conceptually it "replies back", technically it just sends a new `pong`
message to pinger address, defined at (38). It is important, because there is no
request-response pattern, i.e. it "knows" whom to send back the "reply".

Lets move forward.

```
using Supervisor = rl::Supervisor<
    rl::SupervisorBase::min_handlers_amount,
    Pinger,
    Ponger>;
    
using Storage = rl::traits::MessageStorage<rl::message::ChangeState,
                                           rl::message::ChangeStateAck,
                                           message::Ping,
                                           message::Pong>;
```

The standard supervisor; it owns `pinger` and `ponger` actors. The `Storage`
allocates enough space for `Ping` and `Pong` messages.


```
int main(int, char **) {

  app_hw_init();

  /* setup */
  sup.bind(context);
  auto pinger = sup.get_child<0>();      // (39)
  auto ponger = sup.get_child<1>();      // (40)
  pinger->ponger_id = ponger->get_id();  // (41)
  ponger->pinger_id = pinger->get_id();  // (42)
  /* let it polls timer */
  sup.start(true);

  /* main cycle */
  sup.process();   // (43)
  return 0;
}
```

The most iteresting part is the setup-phase (39-40). `pinger` and `ponger` actors
should know each others addresses, and the addresses are available only after
context binding.

When everything is ready, it enters into main loop (43). In it it either delivers
`rotor-light` messages or waits, until the next event time occurs. It uses
**busy waiting** by actively polling (querying) timer, whether the next event time
happend. As usually for busy waiting, it consumes 100% CPU time, which is common
strategy for embedded/real-time applications.

It is possible however do something else, instead of endless timer polling, i.e.
do CPU sleep (and consume less current and do less CO2 emission). See the
next section.

## ping-pong messaging, await the next event in power-save mode

The code for this example is located at `examples/atmega328p/ping-pong-await.cpp`.
From user point of view the example does the same as the previous one:
it sends `ping` message, receives `pong` message, blinks with LED and after some
delay the procedure repeats.

However, the noteable difference is in the delay: in the previous example it
endlessly polls the timer whether the time arrives for the next event burning
CPU cycles, in the current example it does energy-efficient sleeping while
there is noting to do (i.e. no messages) between events.

As the main logic is the same, the artor-related code is also the same; only
`main()` function differs. 

```
int main(int, char **) {
  app_hw_init();

  /* allocate */
  Queue queue;
  Planner planner;
  rl::Context context{&queue, &planner, &get_now};
  Supervisor sup;

  /* setup */
  sup.bind(context);
  auto pinger = sup.get_child<0>();
  auto ponger = sup.get_child<1>();
  pinger->ponger_id = ponger->get_id();
  ponger->pinger_id = pinger->get_id();
  /* let it polls timer */
  sup.start(false);  // (44)

  /* main cycle */
  while (true) {                                   // (45)
    sup.process();                                 // (46)
    auto next_event_time = planner.next_event();   // (47)
    if (next_event_time) {                         // (48)
      perform_sleep(next_event_time);              // (49)
    }
  }
  return 0;
}

```

Firsly, the timer poll via recursively sending self `refresh-timer` message should
be disabled (44). Then the infinite loop (45) should be started, as the supervisor
exits, when it has no more messages to process (46). The first nearby event should
be extracted from planner (47), if any (48), and then perform platform-specific
sleep until the event. The event handler will be actually processed upon the next
loop iteration in (46).

## integration

Lets suppose, that there is a need to read a custom port on idle or perform some
I/O activity, maybe indirecly via calling some other library on each iteration.
How can that be done?

One of the ways to accomplish that is shown above: disable timer poll and do
the needed activity istead of entering into powersave mode, or in addition to
the powersave mode.

Then second way is to have a custom supervisor with `on_refhesh_timer` method
overriden, like that:

```
struct MySupervisor : rl::Supervisor<3, MyActor1, MyActor2, ...> {
using Parent = rl::Supervisor<3, MyActor1, MyActor2, ...>; 

void on_refhesh_timer(rl::message::RefreshTime &message) override {
  Parent::on_refhesh_timer(message);
  third_party_library_poll();
}

};

```
